/*
 * Modelo.cpp
 *
 *  Created on: 02/09/2012
 *      Author: rodrigo
 */

#include "Modelo.h"

using namespace std;

Modelo::Modelo(Juego juego, string nombreNivel) {

    LOGUEAR("Seteada velocidad en "+Logger::intToString(juego.parametros.vel_personaje)+" fps.",1);
    pantalla = new Pantalla(juego.pantalla.ancho, juego.pantalla.alto, juego.parametros.margen_scroll);

	unsigned int numNivel = 0;
	for ( ; numNivel < juego.niveles.size(); numNivel++) {
		if (juego.niveles[numNivel].nombre == nombreNivel)
			break;
	}
	Nivel_y nivel = juego.niveles[numNivel];
	
    this->nivel = new Nivel(nivel.fondo, nivel.sonido, nivel.alto, nivel.ancho);
    this->nivel->setPiso(juego.niveles[numNivel].piso);
    this->nivel->setGravedad(juego.niveles[numNivel].gravedad);

	GestionFabricas::Inicializar(getNivel()->getAncho(), getNivel()->getAlto(), getNivel()->getPiso(), getNivel()->getGravedad());
    cargarObstaculos(nivel, juego.templates, juego.tiposObstaculo);
    cargarBonus(juego.tiposBonus);
    cargarPersonajes(nivel, juego.tiposPersonaje, juego.tiposEnemigo, juego.tipoPrincesa);
}

void Modelo::cargarObstaculos(Nivel_y nivel, vector <Template_y> templates, vector<TipoObstaculo_y> tiposObstaculos) {

	GestionTiposObstaculos::Inicializar(tiposObstaculos);
	
	string path_imagen;
	string msg;

	for (unsigned int i = 0; i < nivel.escaleras.size(); i++) {

		for (unsigned int j = 0; j < templates.size(); j++)
			if( templates[j].nombre == nivel.escaleras[i].imagen )
				path_imagen = templates[j].archivo;

		Escalera* escalera = new Escalera (nivel.escaleras[i].x, nivel.escaleras[i].y, path_imagen, nivel.escaleras[i].ancho,
							nivel.escaleras[i].alto, getNivel()->getAncho(), getNivel()->getAlto());
        v_obstaculos.push_back(escalera);
    }

    for (unsigned int i = 0; i < nivel.plataformas.size(); i++) {

        for (unsigned int j = 0; j < templates.size(); j++)
            if( templates[j].nombre == nivel.plataformas[i].imagen )
                path_imagen = templates[j].archivo;

		Plataforma* plataforma = new Plataforma( nivel.plataformas[i].x, nivel.plataformas[i].y, path_imagen, nivel.plataformas[i].ancho,
								nivel.plataformas[i].alto, getNivel()->getAncho(), getNivel()->getAlto(), nivel.plataformas[i].angulo);
        v_obstaculos.push_back(plataforma);

    }
    
    for (unsigned int i = 0; i < nivel.obstaculos.size(); i++) {

        string obstaculo_nombre = nivel.obstaculos[i].tipo;
        int obstaculo_x      = nivel.obstaculos[i].x;
        int obstaculo_y      = nivel.obstaculos[i].y;
			
		if (obstaculo_nombre == "CajaInterrogacion") {
			CajaInterrogacion* cajaInterrogacion = new CajaInterrogacion(obstaculo_x, obstaculo_y, getNivel()->getAncho(), getNivel()->getAlto());
			GestionTiposObstaculos::AsignarTipoObstaculo(cajaInterrogacion);
			v_estaticos.push_back(cajaInterrogacion);
		}
		else if (obstaculo_nombre == "Caneria") {
			Orientacion orientacion = (nivel.obstaculos[i].orientacion == "izquierda") ? Izquierda : Derecha;
			Caneria* caneria = new Caneria(obstaculo_x, obstaculo_y, getNivel()->getAncho(), getNivel()->getAlto(), orientacion);
			GestionTiposObstaculos::AsignarTipoObstaculo(caneria);
			v_estaticos.push_back(caneria);
		}
		else if (obstaculo_nombre == "CamaElastica") {
			CamaElastica* camaElastica = new CamaElastica(obstaculo_x, obstaculo_y, getNivel()->getAncho(), getNivel()->getAlto());
			GestionTiposObstaculos::AsignarTipoObstaculo(camaElastica);
			v_estaticos.push_back(camaElastica);
		}
		else if (obstaculo_nombre == "CajaPow") {
			CajaPow* cajaPow = new CajaPow(obstaculo_x, obstaculo_y, getNivel()->getAncho(), getNivel()->getAlto());
			GestionTiposObstaculos::AsignarTipoObstaculo(cajaPow);
			v_estaticos.push_back(cajaPow);
			v_cajaPow.push_back(cajaPow);
		}
	}
}

void Modelo::cargarBonus(vector <TipoBonus_y> tiposBonus) {
	
	GestionTiposBonus::Inicializar(tiposBonus);
}

void Modelo::cargarPersonajes(Nivel_y nivel, vector<TipoPersonaje_y> tiposPersonaje, vector <TipoEnemigo_y> tiposEnemigos, TipoPrincesa_y tipoPrincesa) {
	
    string  personaje_nombre;
    int     personaje_x;
    int     personaje_y;
    
    GestionTiposEnemigos::Inicializar(tiposEnemigos);
    GestionTiposPersonaje::Inicializar(tiposPersonaje);
    GestionTipoPrincesa::Inicializar(tipoPrincesa);
    
    vector<string> listaJugadores = GestionTiposPersonaje::getListaTipos();
    vector<string> listaEnemigos = GestionTiposEnemigos::getListaTipos();

    for (unsigned int i = 0; i < nivel.personajes.size(); i++) {

        personaje_nombre = nivel.personajes[i].tipo;
        personaje_x      = nivel.personajes[i].x;
        personaje_y      = nivel.personajes[i].y;
        
        if (personaje_nombre == "Princesa") {
			Orientacion orientacion = (nivel.personajes[i].orientacion == "izquierda") ? Izquierda : Derecha;
			princesa = new Princesa(personaje_x, personaje_y, getNivel()->getAncho(), getNivel()->getAlto(), orientacion);
			GestionTipoPrincesa::AsignarTipoPrincesa(princesa);
			continue;
		}
		
        unsigned int posicionJugadores = find(listaJugadores.begin(), listaJugadores.end(), personaje_nombre) - listaJugadores.begin();
        unsigned int posicionEnemigos = find(listaEnemigos.begin(), listaEnemigos.end(), personaje_nombre) - listaEnemigos.begin();
        
        if (posicionEnemigos < listaEnemigos.size()) {
			
			if (personaje_nombre == "Mono") {
				
				Orientacion orientacion = (nivel.personajes[i].orientacion == "izquierda") ? Izquierda : Derecha;
				Mono* mono = new Mono(personaje_x, personaje_y, getNivel()->getAncho(), getNivel()->getAlto(), orientacion);
				GestionTiposEnemigos::AsignarTipoEnemigo(mono);
				v_estaticos.push_back(mono);
			}
		}
        else if (posicionJugadores < listaJugadores.size()) {
        
			Personaje* personaje = new Personaje(personaje_x, personaje_y, getNivel()->getAncho(), getNivel()->getAlto(), personaje_nombre);
			GestionTiposPersonaje::AsignarTipoPersonaje(personaje, personaje_nombre);
			
			if (personaje_x > nivel.ancho - personaje->getAncho()/2)
            personaje_x = nivel.ancho - personaje->getAncho()/2;
			if (personaje_x < personaje->getAncho()/2)
				personaje_x = personaje->getAncho()/2;
			if (personaje_y-personaje->getAlto() > nivel.alto)
				personaje_y = nivel.alto;
			if (personaje_y < personaje->getAlto())
				personaje_y = personaje->getAlto();

			personaje->setPosicion(personaje_x - personaje->getAncho()/2, personaje_y - personaje->getAlto());
			personaje->setPiso(nivel.piso);
			personaje->setGravedad(nivel.gravedad);
			personaje->setPeriodoSalto();
			personaje->setAlturaMaximaRelativa();
			v_personajes.push_back( personaje );
		}
    }
}

Modelo::~Modelo() {

	for (unsigned int i = 0; i < v_personajes.size(); i++) {

		if (v_personajes.at(i)->getEstadoVida() == Muerto) {
			v_personajes.erase(v_personajes.begin()+i);
			i--;
		}
	}

    while (!v_obstaculos.empty()) {
        delete v_obstaculos.back();
        v_obstaculos.pop_back();
    }

    delete pantalla;
    delete nivel;
    
    GestionTiposPersonaje::Unset();
    GestionId::Unset();
    GestionSonidos::Unset();
}

vector<Personaje*> Modelo::getListaPersonajes()  {
	
    return v_personajes;
}

vector<Obstaculo*> Modelo::getListaObstaculos()  {
    return v_obstaculos;
}

Pantalla* Modelo::getPantalla() {
    return pantalla;
}

Nivel* Modelo::getNivel(){
    return nivel;
}

void Modelo::addPersonaje(Personaje* personaje){

    v_personajes.push_back(personaje);

}

void Modelo::addObstaculo( Obstaculo obs){
    v_obstaculos.push_back(&obs);
}

void Modelo::setPantalla(Pantalla *pantalla){
    this->pantalla=pantalla;
}

void Modelo::ActualizarEstaticos() {

	for (unsigned int i = 0; i < v_estaticos.size(); i++) {
		if (v_estaticos.at(i)->getEstadoVida() == Muerto) {
			v_estaticos.erase(v_estaticos.begin()+i);
			i--;
		}
	}
	for (unsigned int k=0; k<v_cajaPow.size(); k++) {
		v_cajaPow.at(k)->setEnemigos(v_movibles);
	}
}

void Modelo::ActualizarMovibles() {
	
	for (unsigned int i = 0; i < v_movibles.size(); i++) {
		
		if (v_movibles.at(i)->getEstadoVida() == Muerto) {
			v_movibles.erase(v_movibles.begin()+i);
			i--;
		}
	}
}

void Modelo::ActualizarPersonajes() {
	
	for (unsigned int i = 0; i < v_personajes.size(); i++) {
		
		if (v_personajes.at(i)->getEstadoVida() == Muerto) {
			v_personajes.erase(v_personajes.begin()+i);
			i--;
		}
	}
}

vector< pair < pair<idImagen_t, int> , Punto> > Modelo::getDibujablesObstaculos(Uint32 t_juego) {
	
	vector< pair < pair<idImagen_t, int> , Punto> > dibujables;
	
	for (unsigned int i = 0; i < v_obstaculos.size(); i++) {
		pair< pair<idImagen_t, int>, Punto> dibujable(v_obstaculos.at(i)->getDibujable(t_juego), v_obstaculos.at(i)->getPosicion());
		dibujables.push_back(dibujable);
	}
	
	return dibujables;
}

vector< pair < pair<idImagen_t, int> , Punto> > Modelo::getDibujablesEstaticos(Uint32 t_juego) {
	
	vector<ObjetoEstatico*> estaticos = GestionFabricas::getEstaticosCreados();
	for (unsigned int i=0; i<estaticos.size(); i++) {
		ObjetoEstatico* objetoEstatico = estaticos.at(i);
		objetoEstatico->setLastTime(t_juego);
		v_estaticos.push_back(objetoEstatico);
	}
	
	vector< pair < pair<idImagen_t, int> , Punto> > dibujables;

	for (unsigned int i = 0; i < v_estaticos.size(); i++) {
		pair< pair<idImagen_t, int>, Punto> dibujable(v_estaticos.at(i)->getDibujable(t_juego), v_estaticos.at(i)->getPosicion());
		dibujables.push_back(dibujable);
	}
	
	dibujables.push_back(pair< pair<idImagen_t, int>, Punto> (princesa->getDibujable(t_juego), princesa->getPosicion()));
	
	return dibujables;
}

vector< pair < pair<idImagen_t, int> , Punto> > Modelo::getDibujablesMovibles(Uint32 t_juego) {
		
	vector<ObjetoMovible*> nuevosMovibles = GestionFabricas::getMoviblesCreados();
	for (unsigned int i=0; i<nuevosMovibles.size(); i++) {
		ObjetoMovible* objetoMovible = nuevosMovibles.at(i);
		objetoMovible->setLastTime(t_juego);
		objetoMovible->setLastTimeActualizar(t_juego);
		v_movibles.push_back(objetoMovible);
	}
	
	vector< pair < pair<idImagen_t, int> , Punto> > dibujables;

	vector<ObjetoMovible*> v_per;
	for (unsigned int j=0; j<v_personajes.size(); j++) {
		v_per.push_back(v_personajes.at(j));
	}

	for (unsigned int i = 0; i < v_movibles.size(); i++) {
		pair< pair<idImagen_t, int>, Punto> dibujable(v_movibles.at(i)->getDibujable(t_juego, v_estaticos, v_obstaculos, v_movibles, princesa, v_per), v_movibles.at(i)->getPosicion());
		dibujables.push_back(dibujable);
	}
	
	return dibujables;
}

vector< pair < pair<idImagen_t, int> , Punto> > Modelo::getDibujablesPersonajes(vector<Personaje*> v_personajes, Uint32 t_juego) {
	
	vector< pair < pair<idImagen_t, int> , Punto> > dibujables;

	vector<ObjetoMovible*> v_per;
	for (unsigned int j=0; j<v_personajes.size(); j++) {
		v_per.push_back(v_personajes.at(j));
	}

	for (unsigned int i = 0; i < v_personajes.size(); i++) {
		pair< pair<idImagen_t, int>, Punto> dibujable(v_personajes.at(i)->getDibujable(t_juego, v_estaticos, v_obstaculos, v_movibles, princesa, v_per), v_personajes.at(i)->getPosicion());
		dibujables.push_back(dibujable);
	}
	
	return dibujables;
}

vector< pair<vector< pair<int, int> >, Punto> > Modelo::getSonidosPersonajes(vector<Personaje*> personajes) {
	
	vector< pair<vector< pair<int, int> >, Punto> > sonidos;
	
	for (unsigned int i = 0; i < v_personajes.size(); i++) {
		pair<vector< pair<int, int> >, Punto> sonido(v_personajes.at(i)->getSonidos(), v_personajes.at(i)->getPosicion());
		sonidos.push_back(sonido);
	}
	
	return sonidos;
}

string Modelo::armarPaqueteObstaculos() {
								
	std::string paquete = "";
	
	vector< pair < pair<idImagen_t, int> , Punto> > dibujablesObstaculos = getDibujablesObstaculos(0);
	
	for (unsigned int i=0; i<dibujablesObstaculos.size(); i++) {
		pair < pair<idImagen_t, int> , Punto> dibujable = dibujablesObstaculos.at(i);
		paquete+=Logger::intToString(dibujable.first.first)+";"+Logger::intToString(dibujable.first.second)+";"+Logger::intToString(dibujable.second.getX())+";"+Logger::intToString(dibujable.second.getY())+"#";
	}

	return paquete;
}

string Modelo::armarPaqueteObjetos(vector< pair < pair<idImagen_t, int> , Punto> > dibujablesEstaticos,
							vector< pair < pair<idImagen_t, int> , Punto> > dibujablesMovibles) {
								
	std::string paquete = "";
	
	for (unsigned int i=0; i<dibujablesEstaticos.size(); i++) {
		pair < pair<idImagen_t, int> , Punto> dibujable = dibujablesEstaticos.at(i);
		paquete+=Logger::intToString(dibujable.first.first)+";"+Logger::intToString(dibujable.first.second)+";"+Logger::intToString(dibujable.second.getX())+";"+Logger::intToString(dibujable.second.getY())+"#";
	}
	
	for (unsigned int i=0; i<dibujablesMovibles.size(); i++) {
		pair < pair<idImagen_t, int> , Punto> dibujable = dibujablesMovibles.at(i);
		paquete+=Logger::intToString(dibujable.first.first)+";"+Logger::intToString(dibujable.first.second)+";"+Logger::intToString(dibujable.second.getX())+";"+Logger::intToString(dibujable.second.getY())+"#";
	}

	return paquete;
}

string Modelo::armarPaquetePersonajes(vector< pair < pair<idImagen_t, int> , Punto> > dibujablesPersonajes) {
								
	std::string paquete = "";
	
	for (unsigned int i=0; i<dibujablesPersonajes.size(); i++) {
		pair < pair<idImagen_t, int> , Punto> dibujable = dibujablesPersonajes.at(i);
		paquete += Logger::intToString(dibujable.first.first) + ";" + Logger::intToString(dibujable.first.second) + ";" + Logger::intToString(dibujable.second.getX()) + ";" + Logger::intToString(dibujable.second.getY()) + "#";
	}
	
	return paquete;
}

string Modelo::armarPuntajes(vector<Personaje*> personajes) {

	string mensajePuntajes = "";
	for (unsigned int i=0; i<personajes.size(); i++) {
		
		mensajePuntajes += "<";
		
		string puntos = Logger::intToString(300) + ";" + Logger::intToString(personajes.at(i)->getPuntaje());
		mensajePuntajes += puntos + "#";
		
		string mensajeVidaExtra = Logger::intToString(GestionTiposBonus::idPrincipalVidaExtra) + ";" + Logger::intToString(personajes.at(i)->getVidas());
		mensajePuntajes +=  mensajeVidaExtra + "#";
		
		if ( personajes.at(i)->getArmadura() == true ) {
			string mensajeArmadura = Logger::intToString(GestionTiposBonus::idPrincipalArmadura)+ ";" + "";
			mensajePuntajes += mensajeArmadura + "#";
		}
		
		if ( personajes.at(i)->getInvencibilidad() == true ) {
			string mensajeEstrellaInvencibilidad = Logger::intToString(GestionTiposBonus::idPrincipalEstrellaInvencibilidad) + ";" + "";
			mensajePuntajes += mensajeEstrellaInvencibilidad + "#";
		}
		
		if ( personajes.at(i)->getVolatil() == true ) {
			string mensajeVolador = Logger::intToString(GestionTiposBonus::idPrincipalVolador) + ";" + "";
			mensajePuntajes += mensajeVolador + "#";
		}
		
		mensajePuntajes += ">";
	}

	return mensajePuntajes;

}

string Modelo::armarSonidos(vector< pair<vector< pair<int, int> >, Punto> > sonidos) {
	
	string mensaje;
	for (unsigned int i=0; i<sonidos.size(); i++) {
		
		string mensaje_aux;
		for (unsigned int j=0; j<sonidos.at(i).first.size(); j++) {
			mensaje_aux += Logger::intToString(sonidos.at(i).first.at(j).first) + ";" + Logger::intToString(sonidos.at(i).first.at(j).second) + ":" ;
		}
		if (mensaje_aux != "")
			mensaje += mensaje_aux + ";" + Logger::intToString(sonidos.at(i).second.getX()) + ";" + Logger::intToString(sonidos.at(i).second.getY()) + "#";
	}
	return "<" + mensaje + ">";
}

bool Modelo::EsFinJuego() {
	
	if (!princesa->Rescatada()) return false;
	return true;
}

string Modelo::getNombreGanador() {
	
	if (!princesa->Rescatada()) return "";
	if (v_personajes.size() <= 0) return "";
	
	int ganador = 0;
	for (unsigned int i=0; i<v_personajes.size(); i++) {	
		if (v_personajes.at(ganador)->getPuntaje() < v_personajes.at(i)->getPuntaje())
			ganador = i;
		v_personajes.at(i)->Perder();
	}
	
	v_personajes.at(ganador)->Ganar();
	return v_personajes.at(ganador)->getNombre();
}
